package com.zwq.service.impl;

import com.zwq.pojo.dto.MachineDto;
import com.zwq.pojo.dto.MachineStatsDto;
import com.zwq.pojo.entity.Machine;
import com.zwq.pojo.request.user.machine.MachineRequest;
import com.zwq.repository.MachineRepository;
import com.zwq.service.MachineService;
import com.zwq.util.BaiduTokenUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class MachineServiceImpl implements MachineService {

    private final MachineRepository machineRepository;
    private final BaiduTokenUtil baiduTokenUtil;

    @Value("${baidu.api.url}")
    private String API_URL_PREFIX;

    @Override
    public MachineStatsDto getStatistics(Map<String, String> filters) {
        MachineStatsDto dto = new MachineStatsDto();
        List<Machine> machines = filterMachines(filters);

        // 类型分布
        List<Object[]> typeCounts = machineRepository.countByType();
        dto.setTypeDistribution(typeCounts.stream()
                .map(row -> {
                    MachineStatsDto.DistributionItem item = new MachineStatsDto.DistributionItem();
                    item.setName((String) row[0]);
                    item.setValue(((Number) row[1]).intValue());
                    return item;
                })
                .collect(Collectors.toList()));

        // 状态分布
        List<Object[]> statusCounts = machineRepository.countByStatus();
        dto.setStatusDistribution(statusCounts.stream()
                .map(row -> {
                    MachineStatsDto.DistributionItem item = new MachineStatsDto.DistributionItem();
                    item.setName((String) row[0]);
                    item.setValue(((Number) row[1]).intValue());
                    return item;
                })
                .collect(Collectors.toList()));

        // 使用频率
        LocalDateTime start = filters.get("startDate") != null && !filters.get("startDate").isEmpty()
                ? LocalDateTime.parse(filters.get("startDate") + "T00:00:00")
                : LocalDateTime.now().minusMonths(1);
        LocalDateTime end = filters.get("endDate") != null && !filters.get("endDate").isEmpty()
                ? LocalDateTime.parse(filters.get("endDate") + "T23:59:59")
                : LocalDateTime.now();
        List<Object[]> usageCounts = machineRepository.sumUsageCountByDate(start, end);
        dto.setUsageFrequency(usageCounts.stream()
                .map(row -> {
                    MachineStatsDto.UsageFrequencyItem item = new MachineStatsDto.UsageFrequencyItem();
                    item.setDate(row[0].toString());
                    item.setCount(((Number) row[1]).intValue());
                    return item;
                })
                .collect(Collectors.toList()));

        // 故障率
        List<Object[]> failureCounts = machineRepository.countFailuresByName();
        dto.setFailureRate(failureCounts.stream()
                .map(row -> {
                    MachineStatsDto.FailureRateItem item = new MachineStatsDto.FailureRateItem();
                    item.setName((String) row[0]);
                    item.setValue(((Number) row[1]).intValue());
                    return item;
                })
                .collect(Collectors.toList()));

        return dto;
    }

    @Override
    public Page<MachineDto> getMachineList(Map<String, String> filters) {
        int page = Integer.parseInt(filters.getOrDefault("page", "1")) - 1;
        int size = Integer.parseInt(filters.getOrDefault("size", "10"));
        String number = filters.get("machineNumber") != null && !filters.get("machineNumber").isEmpty() ? filters.get("machineNumber") : null;
        String name = filters.get("machineName") != null && !filters.get("machineName").isEmpty() ? filters.get("machineName") : null;
        String type = filters.get("machineCategory") != null && !filters.get("machineCategory").isEmpty() ? filters.get("machineCategory") : null;
        Integer ownerId = filters.get("ownerId") != null && !filters.get("ownerId").isEmpty() ? Integer.parseInt(filters.get("ownerId")) : null;
        LocalDateTime start = filters.get("startDate") != null && !filters.get("startDate").isEmpty()
                ? LocalDateTime.parse(filters.get("startDate") + "T00:00:00")
                : null;
        LocalDateTime end = filters.get("endDate") != null && !filters.get("endDate").isEmpty()
                ? LocalDateTime.parse(filters.get("endDate") + "T23:59:59")
                : null;

        List<Machine> machines = machineRepository.findByFilters(number, name, type, ownerId, start, end);
        List<MachineDto> dtos = machines.stream().map(MachineDto::convertBy).collect(Collectors.toList());

        int startIndex = page * size;
        int endIndex = Math.min(startIndex + size, dtos.size());
        List<MachineDto> pagedDtos = startIndex < dtos.size() ? dtos.subList(startIndex, endIndex) : List.of();

        return new PageImpl<>(pagedDtos, PageRequest.of(page, size), dtos.size());
    }

    @Override
    public byte[] exportStatistics(Map<String, String> filters) {
        MachineStatsDto stats = getStatistics(filters);
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             PrintWriter writer = new PrintWriter(baos)) {
            writer.println("类型分布");
            writer.println("类型,数量");
            stats.getTypeDistribution().forEach(item -> writer.println(item.getName() + "," + item.getValue()));

            writer.println("\n状态分布");
            writer.println("状态,数量");
            stats.getStatusDistribution().forEach(item -> writer.println(item.getName() + "," + item.getValue()));

            writer.println("\n使用频率");
            writer.println("日期,使用次数");
            stats.getUsageFrequency().forEach(item -> writer.println(item.getDate() + "," + item.getCount()));

            writer.println("\n故障率");
            writer.println("机器名称,故障次数");
            stats.getFailureRate().forEach(item -> writer.println(item.getName() + "," + item.getValue()));

            writer.flush();
            return baos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("导出失败", e);
        }
    }

    @Override
    public List<MachineDto> predictMachineStatus() {
        List<Machine> machines = machineRepository.findAll();
        String apiUrl = API_URL_PREFIX + baiduTokenUtil.getAccessToken();

        return machines.stream().map(machine -> {
            MachineDto dto = MachineDto.convertBy(machine);
            String requestBody = getRequestBody(machine);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);

            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.postForObject(apiUrl, entity, String.class);

            if (response == null) {
                throw new RuntimeException("AI API response is null");
            }
            String aiResult = parseAiResult(response);
            String formattedResult = aiResult
                    .replace("\\n", "\n")
                    .replace("\\t", "\t");

            machine.setPrediction(formattedResult);
            machineRepository.save(machine);

            log.info("Machine Predict Request AI Result: \n\t {}", aiResult);

            dto.setStatus(aiResult.contains("故障") ? "PREDICTED_FAULT" : machine.getStatus());
            dto.setPrediction(machine.getPrediction());
            return dto;
        }).collect(Collectors.toList());
    }

    private static String getRequestBody(Machine machine) {
        String input = String.format(
                "请根据以下农业机器数据分析其状态并预测未来可能的问题。" +
                        "机器名称：%s，使用次数：%d次，状态：%s，注册时间：%s，类型：%s。",
                machine.getName(), machine.getUsageCount(), machine.getStatus(), machine.getRegisterTime(), machine.getType()
        );

        return String.format(
                "{\"messages\": [{\"role\": \"user\", \"content\": \"%s\"}], " +
                        "\"temperature\": 0.3, " +
                        "\"model\": \"ERNIE-Speed-128K\"}",
                input
        );
    }

    private String parseAiResult(String response) {
        return response.split("\"result\":\"")[1].split("\"")[0];
    }

    private List<Machine> filterMachines(Map<String, String> filters) {
        String number = filters.get("machineNumber") != null && !filters.get("machineNumber").isEmpty() ? filters.get("machineNumber") : null;
        String name = filters.get("machineName") != null && !filters.get("machineName").isEmpty() ? filters.get("machineName") : null;
        String type = filters.get("machineCategory") != null && !filters.get("machineCategory").isEmpty() ? filters.get("machineCategory") : null;
        Integer ownerId = filters.get("ownerId") != null && !filters.get("ownerId").isEmpty() ? Integer.parseInt(filters.get("ownerId")) : null;
        LocalDateTime start = filters.get("startDate") != null && !filters.get("startDate").isEmpty()
                ? LocalDateTime.parse(filters.get("startDate") + "T00:00:00")
                : null;
        LocalDateTime end = filters.get("endDate") != null && !filters.get("endDate").isEmpty()
                ? LocalDateTime.parse(filters.get("endDate") + "T23:59:59")
                : null;

        return machineRepository.findByFilters(number, name, type, ownerId, start, end);
    }

    @Override
    public MachineDto addMachine(MachineRequest request) {
        Machine machine = new Machine();
        machine.setNumber(request.getNumber());
        machine.setName(request.getName());
        machine.setType(request.getType());
        machine.setStatus(request.getStatus());
        machine.setUsageCount(request.getUsageCount() != null ? request.getUsageCount() : 0);
        machine.setUrl(request.getUrl());
        machine.setOwnerId(request.getOwnerId());
        machine.setRegisterTime(LocalDateTime.now());
        Machine saved = machineRepository.save(machine);
        return MachineDto.convertBy(saved);
    }

    @Override
    public MachineDto updateMachine(MachineRequest request) {
        Machine machine = machineRepository.findById(request.getId())
                .orElseThrow(() -> new RuntimeException("机器不存在"));
        machine.setNumber(request.getNumber());
        machine.setName(request.getName());
        machine.setType(request.getType());
        machine.setStatus(request.getStatus());
        machine.setUsageCount(request.getUsageCount() != null ? request.getUsageCount() : machine.getUsageCount());
        machine.setUrl(request.getUrl());
        machine.setOwnerId(request.getOwnerId());
        Machine updated = machineRepository.save(machine);
        return MachineDto.convertBy(updated);
    }

    @Override
    public void deleteMachine(Long id) {
        Machine machine = machineRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("机器不存在"));
        machineRepository.delete(machine);
    }
}